home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / ddj0190.arc / JAMES.LST < prev    next >
File List  |  1989-12-19  |  35KB  |  1,312 lines

  1. _REAL-TIME ANIMATION_
  2. by Rahner James
  3.  
  4. [LISTING ONE]
  5.  
  6.  
  7.     .model    small, c
  8.     .286    ; This directive can be used to optimize procedure entry
  9.         ; but not much else.  I avoided all non-8088 commands
  10.     comment \
  11.             EGA Sprite Drivers for C
  12.         Copyright (c) February 1989, Ryu Consulting, Inc.
  13.             (916) 722 - 1939 anytime
  14.  
  15.             Written by Rahner James, CS
  16.  
  17.     This is a full functioning sprite driver for EGA graphics
  18.     adaptors.  The sprite are given to the routines as a linked list
  19.     of sprite structures.  All the function are re-entrant and can be
  20.     part of a multi-tasking system.  The sprite structures are intended
  21.     to reside in far memory.  The sprite can exist on any pixel boundary.
  22.     These were intended to be called from some C program, but probably
  23.     can be modified for some other language.  This must be assembled with 
  24.     Microsoft MASM version 5.0 or later since I make use of local
  25.     variables, forward/backward jumps and models.  Expect to get some
  26.     incorrect size warnings because MASM doesn't seem to recognize its own
  27.     "byte ptr" and "word ptr" operators when used with words and dwords.
  28.  
  29.     \
  30. ; ****************************************************************************
  31. ;    EQUATES
  32. ; ****************************************************************************
  33.  
  34. EOI        equ    20h        ; End Of Interrupt signal
  35. EOI_PORT    equ    20h        ; Port to output the EOI
  36. CRT_MODE    equ    49h
  37. EGA_ADDRESS    equ    63h
  38.  
  39. EGA_PIXELS_WORD equ    16        ; Number of pixels per word
  40. EGA_PIXELS_BYTE equ    8        ; Number of pixels per byte
  41. NUMBER_OF_PLANES equ    4        ; Number of EGA color planes
  42.  
  43. EGA_RETRACE_STATUS    equ    3dah    ; EGA retrace status register
  44. RETRACE_BIT        equ    1 shl 3    ; Bit set to signal a vertical retrace
  45. SEQUENCE_REG        equ    3c4h    ; Sequencer register
  46. GRAPHICS_12        equ    3ceh    ; Graphics 1 & 2 register
  47. MAP_MASK_REG        equ    2    ; Map mask Indexed register
  48. DATA_ROTATE_REG    equ    3    ; Data Rotate Indexed register
  49. DATA_OR        equ    1 shl 4    ; Set to OR data on the EGA
  50. DATA_MOVE        equ    0    ; Write data unmodified onto EGA
  51.  
  52. BOTTOM_LINE        equ    200    ; Lowest pixel line to allow a sprite
  53. RIGHT_SIDE        equ    640    ; Right-most visual pixel allowed
  54.  
  55. ; ****************************************************************************
  56. ;    STRUCTURES
  57. ; ****************************************************************************
  58. ; All sprites are stored on disk using the same internal format.
  59. ; The first word is the width of the sprites in bytes and the second
  60. ; word is the height of the sprite in widths.  Each byte represents
  61. ; one pixel's worth of information.  Bit 7 of the byte is the intensity
  62. ; bit, 0=off.  This allows for 128 colors, black will be 0 or 80h.  The
  63. ; intensity bit set indicates an opaque black surface.  All color
  64. ; translations are table driven.
  65.  
  66. internal_sprite_structure    struc    ; Storage structure used for sprites
  67. int_width    dw    ?        ; Width in bytes for the sprite
  68. int_height    dw    ?        ; Height in widths of the sprite
  69. int_body    db    ?        ; Start of the sprite's body
  70. internal_sprite_structure    ends
  71.  
  72. ega_sprite_structure    struc ; Internal EGA sprite structure
  73. e_animate_ptr    dw    0,0   ; Far ptr to next sprite struct in animation seq.
  74. e_width    dw    ?    ; Width of the sprite in words
  75. e_height    dw    ?     ; Height of sprite in widths
  76. e_body        dw    ?     ; Beginning of body
  77.                   ;.word 0: mask, word 1: sprite
  78.                   ;.throughout the body.  That way you can pull
  79.                   ;.the background up, mask it, OR the sprite,
  80.                   ;.then store the background
  81.                   ; The body is organized into four planes,
  82.                   ;.termed PLANE0 to PLANE3.  Each represents a
  83.                   ;.different color in the EGA spectrum, except
  84.                   ;.PLANE0 which is the intensity bit.
  85. ega_sprite_structure    ends
  86.  
  87. style_structure    struc
  88. style_width    dw    ?        ; Width of each style entry in bytes
  89. style_height    dw    ?        ; Height of each style entry in pixels
  90. style_body    db    ?        ; Start of the style entries
  91. style_structure    ends
  92.  
  93. ; ****************************************************************************
  94. ;    LOCAL DATA STORAGE for DS
  95. ; ****************************************************************************
  96. .data
  97. public        do_page_flip, done_page_flip
  98.     even
  99. do_page_flip    db    0    ; Set to -1 when non-visual page is completed
  100. done_page_flip    db    -1    ; Set to -1 right after page has been swapped
  101. flip_turn    db    4    ; # of interrupts before an EGA page flip
  102.  
  103. old_irq_mask    db    0    ; Old IRQ mask
  104.  
  105. EGA_settings    db    2bh,2bh,2bh,2bh,24h,24h,23h,2eh
  106.         db    0,0,0,0,0,24h,23h,2eh,2bh
  107.  
  108.     even
  109. ega_base_port        dw    ?
  110. default_retrace    label    word
  111. v_retrace_reg        db    11h
  112. v_retrace_value    db    ?
  113.  
  114. .code
  115. ; ****************************************************************************
  116. ;    LOCAL DATA STORAGE for CS
  117. ; ****************************************************************************
  118.  
  119.     even
  120.  
  121. ega_segment    dw    0a800h ; EGA page memory segment being set up
  122. old_vector    dw    0,0    ; Old IRQ-2 vector (as Checkov would say wecter)
  123.  
  124. ; EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  125. ; EGA sprite related routines below this line
  126. ; void    EGA_CONVERT( dest_ptr, source_ptr )
  127. ; Converts long storage format sprite into EGA structure sprite
  128. ; Given:
  129. ;    dest_ptr far -> EGA sprite buffer ready to go
  130. ;    source_ptr far -> disk sprite structure to convert
  131. ; Returns:
  132. ;    EGA sprite buffer set up accordingly
  133.  
  134. ega_convert proc near uses di si ds, dest:dword, source:dword
  135. local    store_width:word, store_height:word
  136. local    source_width:word
  137. local    plane_size:word
  138.     cld
  139.     lds    si, source        ; DS:SI -> source sprite
  140.     les    di, dest        ; ES:DI -> CGA sprite buffer
  141.  
  142.     mov    es:[di], di        ; Make the animate ptr point to itself
  143.     mov    es:[di+2], es
  144.     add    di, E_WIDTH
  145.  
  146.     lodsw                ; Get width in byte pixels
  147.     mov    source_width, ax
  148.     add    ax, EGA_PIXELS_WORD-1    ; Want to include those border pixels
  149.     mov    cl, 4            ; Divide by sixteen to convert one byte
  150.     shr    ax, cl            ;.per pixel to 16 pixels/word for EGA
  151.     mov    bx, ax            ; Use this as our width count
  152.     stosw                ; Store as words/pixels
  153.     lodsw                ; Get height
  154.     mov    store_height, ax
  155.     stosw                ; Move height straight across
  156.     mul    bx            ; AX = Body size in mask/sprite entries
  157.     add    ax, ax            ; AX = body size in words
  158.     add    ax, ax            ; AX = plane size in bytes
  159.     mov    plane_size, ax        ; Save as our plane index
  160.  
  161.     mov    ax, ds            ; Swap DS:SI and ES:DI
  162.     mov    bx, es
  163.     mov    ds, bx
  164.     mov    es, ax
  165.     xchg    di, si
  166.  
  167.     sub    si, 4            ; This is to prep for the next INC
  168. next_row:
  169.     mov    cx, source_width    ; Get source row width
  170. next_word:
  171.     add    si, 4            ; SI -> next word in line
  172.     mov    dx, -1            ; DX = the destination mask
  173.     xor    ax, ax
  174.     mov    [si], dx        ; Set the mask word
  175.     mov    [si+2], ax        ; Clear the sprite word
  176.     mov    bx, plane_size        ; BX offset to next plane
  177.     mov    [si+bx], dx        ; Set the mask word
  178.     mov    [si+bx+2], ax        ; Clear the sprite word
  179.     add    bx, plane_size        ; BX offset to next plane
  180.     mov    [si+bx], dx        ; Set the mask word
  181.     mov    [si+bx+2], ax        ; Clear the sprite word
  182.     add    bx, plane_size        ; BX offset to next plane
  183.     mov    [si+bx], dx        ; Set the mask word
  184.     mov    [si+bx+2], ax        ; Clear the sprite word
  185.  
  186.     mov    dx, 1 shl 7        ; Start at MSB which is pixel LSB
  187. next_pixel_byte:
  188.     jc    next_word        ; Only be set by pixel shift below
  189.     mov    al, es:[di]        ; Get the source pixel byte
  190.     inc    di            ; DI -> next source pixel byte
  191.     or    al, al            ; See if it's anything at all
  192.     jz    end_pixel_byte        ; Skip all the checks
  193.  
  194.     xor    [si], dx        ; Reset the mask bit
  195.     test    al, 1 shl 4        ; Check bit 7
  196.     jz    @F            ; Skip if nothing here
  197.     or    [si+2], dx        ; Place the sprite bit
  198. @@:    mov    bx, plane_size        ; BX -> plane 1 offset
  199.     xor    [si+bx], dx        ; Clear the mask bit
  200.     test    al, 1 shl 7        ; Check bit 6
  201.     jz    @F            ; Skip if nothing here
  202.     or    [si+bx+2], dx        ; Place the sprite bit
  203. @@:    add    bx, plane_size        ; BX -> plane 2 offset
  204.     xor    [si+bx], dx        ; Clear the mask bit
  205.     test    al, 1 shl 6        ; Check bit 5
  206.     jz    @F            ; Skip if nothing here
  207.     or    [si+bx+2], dx        ; Place the sprite bit
  208. @@:    add    bx, plane_size        ; BX -> plane 3 offset
  209.     xor    [si+bx], dx        ; Clear the mask bit
  210.     test    al, 1 shl 5        ; Check bit 4
  211.     jz    end_pixel_byte        ; Skip if nothing here
  212.     or    [si+bx+2], dx        ; Place the sprite bit
  213.  
  214. end_pixel_byte:
  215.     shr    dl, 1            ; Move pixel bit toward MS pixel bit
  216.     rcr    dh, 1
  217.     loop    next_pixel_byte        ; Loop through the pixel bytes
  218.  
  219.     dec    store_height        ; One less row
  220.     jnz    next_row
  221.  
  222.     ret
  223. ega_convert    endp
  224.  
  225. ; EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  226. ; ui EGA_CALCULATE( source_ptr )
  227. ; Calculates the amount of storage needed for an unconverted sprite
  228. ; Given:
  229. ;    source_ptr far -> disk sprite structure to convert
  230. ; Returns:
  231. ;    AX = number of bytes needed to store the converted sprite
  232.  
  233. ega_calculate proc near uses si ds, source:dword
  234.     lds    si, source     ; DS:SI -> disk sprite structure for calculation
  235.     mov    ax, [si]       ; Get the width in bytes
  236.     add    ax, EGA_PIXELS_WORD-1    ; Round up to nearest word
  237.     shr    ax, 4            ; AX = number of words for stoarge
  238.     add    ax, ax            ; AX = number of bytes storage
  239.     add    ax, ax            ; AX = number of globs in one row
  240.     add    ax, ax            ; AX = number of row/planes
  241.     add    ax, ax
  242.     mul    word ptr [si].int_height ; AX = bytes per row * number of rows
  243.     add    ax, E_BODY        ; AX = body size + header size
  244.     ret
  245. ega_calculate    endp
  246.  
  247. ; EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  248. ; void PUT_SPRITE( ui X, ui Y, ega_sprite_structure far *SPRITE_PTR )
  249. ; Maps a sprite list into the display video buffer
  250. ; Sprite is assumed to be 32-bits wide
  251. ; Given:
  252. ;    X = X pixel location of sprite
  253. ;    Y = Y pixel location of sprite
  254. ;    SPRITE_PTR -> sprite structure to put on the screen
  255. ; Returns:
  256. ;    The sprite is mapped onto the screen buffer
  257. put_sprite proc uses di si, x:word, y:word, sprite_ptr:dword
  258.  
  259. local    mask_msw:word            ; OR'ed with the mask dword
  260. local    mask_lsw:word
  261. local    or_msw:word            ; AND'ed with the sprite dword
  262. local    or_lsw:word
  263. local    start_di:word
  264. local    start_si:word
  265. local    sprite_plane_size:word
  266. local    number_of_rows:word
  267. local    shift:byte
  268. local    plane_number:byte
  269.     push    ds
  270.     cmp    y, 200            ; See if below 200
  271.     jc    @F
  272. short_done:
  273.     jmp    done
  274. @@:    cmp    x, 640
  275.     jnc    short_done
  276.  
  277.     cld
  278.     mov    es, ega_segment
  279.     lds    si, sprite_ptr        ; DS:SI -> sprite to be driven
  280.  
  281.     mov    ax, 80            ; Calculate the offset
  282.     mul    y
  283.     mov    cx, x
  284.     mov    di, cx
  285.     and    cl, 7            ; CL = shift value
  286.     mov    shift, cl
  287.     shr    di, 3
  288.     add    di, ax            ; DI -> byte offset
  289.     mov    start_di, di
  290.  
  291.     mov    ax, [si].e_height    ; AX = height of the sprite in rows
  292.     mov    number_of_rows, ax    ; Save for later use
  293.     shl    ax, 3            ; AX *= 8, to get size of 1 sprite plane
  294.     mov    sprite_plane_size, ax
  295.  
  296.     mov    ax, number_of_rows    ; Let's see if it goes too low
  297.     add    ax, y
  298.     sub    ax, BOTTOM_LINE
  299.     jbe    @F            ; Skip if it doesn't
  300.     sub    number_of_rows, ax    ; Update the number of rows
  301.  
  302. @@:    add    si, E_BODY        ; SI -> start of sprite body
  303.     mov    start_si, si
  304.  
  305.     cmp    x, 640-32        ; See if we are going to be right
  306.     ja    short_mask        ; Skip if no mask
  307.     cmp    shift, 0
  308.     jnz    shifted
  309.  
  310.     mov    bl, NUMBER_OF_PLANES
  311. next_plane:
  312.     dec    bl
  313.  
  314.     mov    dx, GRAPHICS_12        ; Talk to EGA control logic
  315.     mov    al, 4
  316.     mov    ah, bl
  317.     out    dx, ax
  318.  
  319.     mov    dx, SEQUENCE_REG    ; Set up the ports for writing as well
  320.     mov    ax, 100h + MAP_MASK_REG
  321.     mov    cl, bl
  322.     shl    ah, cl
  323.     out    dx, ax
  324.  
  325.     mov    cx, number_of_rows
  326. @@:    mov    ax, es:[di]        ; Get the background dword
  327.     mov    dx, es:[di+2]
  328.     and    ax, [si]        ; Do the mask dword
  329.     and    dx, [si+4]
  330.     or    ax, [si+2]        ; Bring on the sprite
  331.     or    dx, [si+6]
  332.     mov    es:[di], ax        ; Replace with new graphic dword
  333.     mov    es:[di+2], dx
  334.     add    si, 8            ; Next row stuff
  335.     add    di, 80
  336.     loop    @B
  337.  
  338.     mov    di, start_di
  339.     mov    si, start_si
  340.     add    si, sprite_plane_size
  341.     mov    start_si, si
  342.     or    bl, bl
  343.     jnz    next_plane
  344.     jmp    done
  345. short_mask:
  346.     jmp    masked
  347.  
  348. shifted:
  349.     mov    plane_number, NUMBER_OF_PLANES-1
  350.     mov    cl, shift
  351.     mov    bh, -1
  352.     shr    bh, cl
  353. next_shift_plane:
  354.     mov    dx, GRAPHICS_12        ; Talk to EGA control logic
  355.     mov    al, 4
  356.     mov    ah, plane_number
  357.     out    dx, ax
  358.  
  359.     mov    dx, SEQUENCE_REG    ; Set up the ports for writing as well
  360.     mov    ax, 100h + MAP_MASK_REG
  361.     mov    cl, plane_number
  362.     shl    ah, cl
  363.     out    dx, ax
  364.  
  365.     mov    ch, byte ptr number_of_rows
  366.     mov    cl, shift
  367. @@:    lodsw                ; Get the sprite mask
  368.     xchg    ah, al            ; Switch them around
  369.     ror    ax, cl
  370.     mov    bl, ah            ; Top CL bits are ones to mask 3rd byte
  371.     not    bh            ; BH = ~BH
  372.     and    bl, bh
  373.     or    ah, bh            ; Now set the top ones of source byte
  374.     mov    dx, es:[di]        ; Get the first destination word
  375.     xchg    ah, al            ; Re-order the mask bytes
  376.     and    dx, ax            ; Mask it
  377.     lodsw                ; Get the sprite
  378.     xchg    ah, al
  379.     ror    ax, cl
  380.     or    dh, al            ; OR DH w/ old AH
  381.     mov    al, ah            ; Save the upper bits
  382.     and    ah, bh            ; Mask off other bits
  383.     not    bh            ; BH = BH
  384.     and    al, bh            ; Cut out the rotunds
  385.     or    dl, al            ; OR least sig. bytes
  386.     mov    es:[di], dx        ; Save that first word, whew!
  387.  
  388.     mov    dl, ah            ; DL = pushed up sprite bits
  389.  
  390.     lodsw                ; Get the next sprite mask
  391.     xchg    ah, al            ; Switch them around
  392.     ror    ax, cl
  393.     mov    dh, ah            ; DH = MS shifted mask bits
  394.     and    ah, bh            ; Get rid of shifted bits
  395.     or    ah, bl            ; OR with shifted mask, previous byte
  396.     or    dh, bh            ; Add on the mask
  397.     xchg    ah, al            ; AH:AL back to normal
  398.     and    es:[di+4], dh        ; Easy way to get rid of DH
  399.     mov    bl, dl            ; BL = previous sprite bits
  400.     mov    dx, es:[di+2]        ; Get the destination word
  401.     and    dx, ax            ; Mask it
  402.     lodsw                ; Get the sprite
  403.     xchg    ah, al
  404.     ror    ax, cl
  405.     or    dh, al            ; OR DH w/ old AH
  406.     mov    al, ah            ; Save the upper bits
  407.     not    bh            ; BH = ~BH
  408.     and    ah, bh            ; Mask off other bits
  409.     not    bh            ; BH = BH
  410.     and    al, bh            ; Cut out the rotunds
  411.     or    al, bl
  412.     or    dl, al            ; OR least sig. bytes
  413.     mov    es:[di+2], dx        ; Save that first word, whew!
  414.     or    es:[di+4], ah
  415.  
  416.     add    di, 80
  417.  
  418.     dec    ch
  419.     jnz    @B
  420.  
  421.     mov    di, start_di
  422.     mov    si, start_si
  423.     add    si, sprite_plane_size
  424.     mov    start_si, si
  425.     sub    plane_number, 1
  426.     jc    @F
  427.     jmp    next_shift_plane
  428. @@:    jmp    done
  429.  
  430. masked:
  431.     xor    ax, ax            ; Set up masks and ORs
  432.     mov    mask_lsw, ax
  433.     mov    mask_msw, ax
  434.     dec    ax
  435.     mov    or_lsw, ax
  436.     mov    or_msw, ax
  437.  
  438.     cmp    x, 640-24        ; See if we have masked it already
  439.     jc    @F            ; Skip if we have
  440.     mov    mask_msw, 0ff00h
  441.     mov    or_msw, 0ffh
  442.  
  443.     cmp    x, 640-16
  444.     jc    @F
  445.     mov    mask_msw, -1        ; Make sure nothing gets masked
  446.     mov    or_msw, 0
  447.  
  448.     cmp    x, 640-8        ; See if that's all
  449.     jc    @F
  450.     mov    mask_lsw, 0ff00h
  451.     mov    or_lsw, 0ffh
  452.  
  453. @@:    mov    plane_number, NUMBER_OF_PLANES-1
  454. next_mask_plane:
  455.     mov    dx, GRAPHICS_12        ; Talk to EGA control logic
  456.     mov    al, 4
  457.     mov    ah, plane_number
  458.     out    dx, ax
  459.  
  460.     mov    dx, SEQUENCE_REG    ; Set up the ports for writing as well
  461.     mov    ax, 100h + MAP_MASK_REG
  462.     mov    cl, plane_number
  463.     shl    ah, cl
  464.     out    dx, ax
  465.  
  466.     mov    cx, number_of_rows
  467. @@:    mov    ax, [si]        ; Get the first mask
  468.     mov    dx, [si+4]        ; Get the second mask
  469.     or    ax, mask_lsw
  470.     or    dx, mask_msw
  471.     and    ax, es:[di]        ; Get the background dword
  472.     and    dx, es:[di+2]
  473.     mov    bx, or_lsw        ; Get the OR lsw
  474.     and    bx, [si+2]        ; Bring on the sprite
  475.     or    ax, bx
  476.     mov    bx, or_msw
  477.     and    bx, [si+6]
  478.     or    dx, bx
  479.     mov    es:[di], ax        ; Replace with new graphic dword
  480.     mov    es:[di+2], dx
  481.     add    si, 8            ; Next row stuff
  482.     add    di, 80
  483.     loop    @B
  484.  
  485.     mov    di, start_di
  486.     mov    si, start_si
  487.     add    si, sprite_plane_size
  488.     mov    start_si, si
  489.     sub    plane_number, 1
  490.     jnc    next_mask_plane
  491.     jmp    done
  492.  
  493. done:    pop    ds
  494.     ret
  495. put_sprite    endp
  496.  
  497. ; EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  498. ; void EGA_CLEAR_AREA( ui X1, ui Y1, ui X2, ui Y2 )
  499. ; Clears an area on the EGA display to black
  500. ; Given:
  501. ;    X1,Y1 = X,Y pixel coordinates of the upper left corner
  502. ;    X2,Y2 = X,Y pixel coordinates of the lower right corner
  503. ; Returns:
  504. ;    Rectangular area from X1,Y1 to X2,Y2 (inclusive) cleared to black
  505.  
  506. public ega_clear_area
  507. ega_clear_area proc uses ds si di, x1:word, y1:word, x2:word, y2:word
  508. local    height:word
  509. local    di_start:word
  510. local    word_columns:word
  511. local    di_offset:word
  512.  
  513.     cld
  514.  
  515.     cmp    x1, 640            ; See if too far to the right
  516.     jc    @F
  517.     mov    x1, 0
  518. @@:    cmp    x2, 640
  519.     jc    @F
  520.     mov    x2, 639
  521.  
  522. @@:    mov    ax, y2            ; Check out number of rows
  523.     sub    ax, y1
  524.     jnc    @F            ; See if jerk put them in backwards
  525.     neg    ax
  526. @@:    inc    ax
  527.     mov    bx, ax            ; BX = number of rows
  528.     mov    height, ax
  529.  
  530.     mov    ax, y1            ; Check our starting offset
  531.     mov    cx, 80
  532.     mov    di_offset, cx
  533.     mul    cx
  534.     mov    di, ax
  535.     mov    ax, x1            ; See where we start
  536.     shr    ax, 3
  537.     add    di, ax
  538.  
  539.     mov    ax, x2
  540.     sub    ax, x1
  541.     jnc    @F
  542.     neg    ax
  543. @@:    add    ax, 16
  544.     shr    ax, 4
  545.     jnz    @F
  546.     jmp    done
  547.  
  548. @@:    mov    word_columns, ax
  549.     add    ax, ax
  550.     sub    di_offset, ax
  551.     mov    es, ega_segment
  552.  
  553.     mov    dx, SEQUENCE_REG    ; Set up the ports for writing
  554.     mov    ax, 0f00h+MAP_MASK_REG
  555.     out    dx, ax
  556.  
  557.     mov    dx, di_offset
  558.     xor    ax, ax
  559.     mov    di_start, di
  560. @@:    mov    cx, word_columns
  561.     rep    stosw
  562.     add    di, dx
  563.     dec    bx
  564.     jnz    @B
  565.  
  566. done:    ret
  567. ega_clear_area endp
  568.  
  569. ; EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  570. ; void EGA_INSTALL()
  571. ; Installs IRQ-2 vectors for EGA card
  572. ; Given:
  573. ;    nothing
  574. ; Returns:
  575. ;    -1 if neither EGA or VGA else
  576. ;    EGA interrupt vector installed and enabled
  577. public    ega_install
  578.  
  579. ega_install proc
  580.     mov    ax, 40h            ; ES -> video BIOS data area
  581.     mov    es, ax
  582.  
  583.     mov    dx, es:[EGA_ADDRESS]    ; DX -> CRTC Address port
  584.     mov    ega_base_port, dx    ; Save the port address
  585.  
  586.     mov    ax, 1a00h        ; Read display combination
  587.     int    10h
  588.     cmp    al, 1ah            ; See if EGA
  589.     jne    ega_adaptor
  590.     cmp    bl, 7            ; See if VGA
  591.     je    vga_adaptor
  592.     cmp    bl, 8
  593.     je    vga_adaptor
  594. error_out:
  595.     mov    ax, -1
  596.     jmp    short done
  597.  
  598. ega_adaptor:
  599.     mov    al, es:[CRT_MODE]    ; AL = video BIOS mode number
  600.     mov    bx, offset EGA_settings
  601.     xlat
  602.     jmp    short @F
  603.  
  604. vga_adaptor:
  605.     mov    al, v_retrace_reg    ; AL = Vertical retrace register
  606.     out    dx, al
  607.     inc    dx
  608.     in    al, dx
  609.  
  610. @@:    mov    v_retrace_value, al
  611.  
  612.     mov    done_page_flip, -1
  613.     mov    do_page_flip, 0
  614.  
  615.     xor    ax, ax            ; ES -> base page
  616.     mov    es, ax
  617.     mov    bx, 0ah*4        ; Vector for IRQ 2
  618.     mov    dx, cs
  619.     mov    ax, offset ega_interrupt
  620.  
  621.     cli
  622.     xchg    es:[bx], ax
  623.     xchg    es:[bx+2], dx
  624.     mov    old_vector, ax
  625.     mov    old_vector+2, dx
  626.  
  627.     in    al, 21h            ; Get present mask
  628.     mov    old_irq_mask, al
  629.     and    al, 11111011b
  630.     out    21h, al
  631.  
  632.     mov    dx, ega_base_port
  633.     mov    ax, default_retrace
  634.     and    ah, 11001111b
  635.     out    dx, ax
  636.     jmp    short $+2
  637.     or    ah, 00010000b
  638.     out    dx, ax
  639.     sti
  640.  
  641. done:    ret
  642. ega_install endp
  643.  
  644. ; EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  645. ; void EGA_RIP_OUT()
  646. ; Undoes all the interrupt processing for the EGA
  647. ; Given:
  648. ;    nothing
  649. ; Returns:
  650. ;    EGA interrupt vector removed
  651. public    ega_rip_out
  652. ega_rip_out proc uses es
  653.     mov    ax, old_vector        ; See if installed
  654.     or    ax, old_vector+2
  655.     jz    done            ; Return if not installed
  656.  
  657.     xor    ax, ax            ; ES -> base page
  658.     mov    es, ax
  659.     mov    bx, 0ah*4        ; Vector for IRQ 2
  660.     mov    ax, old_vector
  661.     mov    dx, old_vector+2
  662.     mov    old_vector, 0
  663.     mov    old_vector+2, 0
  664.     cli
  665.     mov    es:[bx], ax
  666.     mov    es:[bx+2], dx
  667.  
  668.     in    al, 21h
  669.     mov    ah, old_irq_mask    ; Restore old interrupt mask
  670.     and    ah, 1 shl 2
  671.     and    al, 11111011b
  672.     or    al, ah
  673.     out    21h, al
  674.  
  675.     mov    dx, 3d4h
  676.     mov    ax, 2b11h
  677.     out    dx, ax
  678.     sti
  679. done:    ret
  680. ega_rip_out endp
  681.  
  682. ; EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  683. ; void EGA_INTERRUPT( void )
  684. ; Handles all the interrupt processing for the EGA controller
  685. ; Given:
  686. ;    This is run at every IRQ-2 spike (ie. vertical retrace)
  687. ; Returns:
  688. ;    If FLIP_TURN is brought to zero, EGA visual pages are swapped
  689. ;    If swap is made, DO_PAGE_FLIP set to 0, DONE_PAGE_FLIP set to -1
  690.  
  691. ega_interrupt proc far
  692.     push    ax
  693.     push    dx
  694.     push    ds
  695.  
  696.     mov    ax, @DATA
  697.     mov    ds, ax
  698.  
  699.     mov    dx, 3c2h        ; DX -> I/O port for input status
  700.     in    al, dx
  701.     test    al, 1 shl 7
  702.     jnz    @F            ; Interrupt is ours
  703.     pushf
  704.     call    dword ptr [old_vector]
  705.     jmp    done
  706.  
  707. @@:    mov    dx, ega_base_port    ; DX -> EGA/VGA register port
  708.     in    al, dx
  709.     push    ax
  710.  
  711.     mov    ax, default_retrace
  712.     and    ah, 11101111b
  713.     out    dx, ax
  714.     jmp    short $+2
  715.  
  716.     mov    al, EOI
  717.     out    EOI_PORT, al
  718.     jmp    short $+2
  719.     sti
  720.  
  721.     dec    flip_turn
  722.     jnz    @F
  723.     mov    flip_turn, 4
  724.     cmp    do_page_flip, 0        ; See if we need to do this
  725.     jz    @F
  726.  
  727.     mov    al, 0ch            ; Select register for page MSB
  728.     mov    ah, byte ptr ega_segment+1
  729.     shl    ah, 4
  730.     out    dx, ax            ; Output the most significant byte
  731.     xor    ega_segment, 800h    ; Swap the active page
  732.     jmp    short $+2
  733.  
  734.     mov    do_page_flip, 0
  735.     mov    done_page_flip, -1
  736.  
  737. @@:    cli
  738.     mov    ax, default_retrace
  739.     and    ah, 11011111b
  740.     or    ah, 00010000b
  741.     out    dx, ax
  742.     jmp    short $+2
  743.     pop    ax
  744.     out    dx, al
  745.  
  746. done:    pop    ds
  747.     pop    dx
  748.     pop    ax
  749.  
  750.     iret
  751. ega_interrupt endp
  752.  
  753.     end
  754.  
  755.  
  756. [LISTING TWO]
  757.  
  758.     comment \
  759.              Sprite Circle Handler
  760.         Copyright (c) February 1989, Ryu Consulting, Inc.
  761.             (916) 722 - 1939 anytime
  762.             Written by Rahner James, CS
  763.         \
  764.  
  765. ; ****************************************************************************
  766. ;    EQUATES
  767. ; ****************************************************************************
  768. MAX_SPRITES    equ    50
  769. ; ****************************************************************************
  770. ;    STRUCTURES
  771. ; ****************************************************************************
  772. sprite_structure struc
  773. animate_ptr    dw    0,0
  774. sprite_width    dw    0        ; Width in words
  775. sprite_height    dw    0        ; Height in pixels
  776. sprite_body    db    ?
  777. sprite_structure ends
  778. struc
  779. x        dw    0
  780. y        dw    0
  781. depth        dw    0
  782. pre_x        dw    0
  783. pre_y        dw    0
  784. dest_x        dw    0
  785. dest_y        dw    0
  786. adder_x    dw    0
  787. adder_y    dw    0
  788. sprite_ptr    dw    0,0
  789. next_node    dw    0
  790. sprite_node    ends
  791. .data
  792. ; ****************************************************************************
  793. ;    DATA VARIABLES and EXTERNAL DEFINITIONS
  794. ; ****************************************************************************
  795. extrn    done_page_flip:byte, do_page_flip:byte
  796. extrn    min_x:word, min_y:word, max_y:word, max_x:word
  797.  
  798. first_sprite    dw    0
  799. public    sprite_list
  800. sprite_list    sprite_node    MAX_SPRITES dup(<>)
  801.  
  802. pre_max_x    dw    639
  803. pre_max_y    dw    199
  804. pre_min_x    dw    0
  805. pre_min_y    dw    0
  806.  
  807. .code
  808. ; ****************************************************************************
  809. ;    ROUTINES and EXTERNAL CODE DEFINITIONS
  810. ; ****************************************************************************
  811. extrn    do_background:near, put_sprite:near
  812.  
  813. ; ****************************************************************************
  814. ; void DO_SPRITE_LIST( void )
  815. ; Sets up the sprites on the unviewed back page
  816. ; Given:
  817. ;    A sprite list has been created and is stored in the array SPRITE_LIST
  818. ; Returns:
  819. ;    If DONE_PAGE_FLIP is 0, no processing is done
  820. ;    else all sprites in the sprite list are put on the non-visual page
  821. ;     then DONE_PAGE_FLIP is set to 0 and DO_PAGE_FLIP is set to -1
  822.  
  823. do_sprite_list proc uses si
  824.     cmp    done_page_flip, 0    ; See if we need to do this
  825.     jnz    @F
  826.     jmp    done
  827. @@:    call    do_background
  828.  
  829.     mov    ax, pre_max_x
  830.     mov    max_x, ax
  831.     mov    ax, pre_max_y
  832.     mov    max_y, ax
  833.     mov    ax, pre_min_x
  834.     mov    min_x, ax
  835.     mov    ax, pre_min_y
  836.     mov    min_y, ax
  837.  
  838.     xor    ax, ax            ; Clear out some variables
  839.     mov    pre_max_x, ax
  840.     mov    pre_max_y, ax
  841.     dec    ax
  842.     mov    pre_min_x, ax
  843.     mov    pre_min_y, ax
  844.  
  845.     mov    si, first_sprite    ; SI -> sprite node to start with
  846. next_sprite:
  847.     or    si, si            ; See if this is a NULL pointer
  848.     jnz    @F
  849.     jmp    almost_done
  850.  
  851. @@:    mov    ax, [si].x
  852.     mov    [si].pre_x, ax
  853.  
  854.     cmp    [si].dest_x, ax        ; See if we are already there
  855.     je    no_add_x        ; Skip if we are
  856.     mov    cx, [si].dest_x        ; Get our absolute value
  857.     sub    cx, [si].x
  858.     jnc    @F
  859.     neg    cx
  860. @@:    add    ax, [si].adder_x
  861.     mov    [si].x, ax
  862.     sub    ax, [si].dest_x
  863.     jnc    @F
  864.     neg    ax
  865. @@:    cmp    cx, ax
  866.     jnc    no_add_x
  867.     mov    ax, [si].dest_x
  868.     mov    [si].x, ax
  869. no_add_x:
  870.     mov    ax, [si].y
  871.     mov    [si].pre_y, ax
  872.  
  873.     cmp    [si].dest_y, ax        ; See if we are already there
  874.     je    no_add_y        ; Skip if we are
  875.     mov    cx, [si].dest_y        ; Get our absolute value
  876.     sub    cx, [si].y
  877.     jnc    @F
  878.     neg    cx
  879. @@:    add    ax, [si].adder_y
  880.     mov    [si].y, ax
  881.     sub    ax, [si].dest_y
  882.     jnc    @F
  883.     neg    ax
  884. @@:    cmp    cx, ax
  885.     jnc    no_add_y
  886.     mov    ax, [si].dest_y
  887.     mov    [si].y, ax
  888. no_add_y:
  889.     cmp    [si].y, 200        ; See if beyond bottom line
  890.     jnc    pre_next_sprite
  891.     mov    ax, [si].x        ; See if we need to update some things
  892.     cmp    ax, 640            ; See if beyond right column
  893.     jnc    pre_next_sprite
  894.     cmp    ax, pre_min_x        ; See if pre_x < min_x
  895.     jnc    @F            ; Skip if not
  896.     mov    pre_min_x, ax        ; Update with new MIN_X
  897.  
  898. @@:    mov    ax, [si].y        ; See if need to update min_y
  899.     cmp    ax, pre_min_y
  900.     jnc    @F
  901.     mov    pre_min_y, ax
  902.  
  903. @@:    les    bx, dword ptr [si].sprite_ptr    ; ES:BX -> sprite structure
  904.  
  905.     mov    ax, es:[bx].sprite_width
  906.     inc    ax
  907.     if    (@Cpu AND 2)
  908.     shl    ax, 4            ; AX = AX * 16
  909.     else
  910.     rept    4
  911.     add    ax, ax
  912.     endm
  913.     endif
  914.     add    ax, [si].x
  915.     cmp    pre_max_x, ax        ; See if > max_x
  916.     jnc    @F            ; Jump if not
  917.     mov    pre_max_x, ax        ; Assume we are going to save it
  918.  
  919. @@:    mov    ax, es:[bx].sprite_height
  920.     add    ax, [si].y
  921.     cmp    pre_max_y, ax        ; See if > max_x
  922.     jnc    @F            ; Jump if not
  923.     mov    pre_max_y, ax        ; Assume we are going to save it
  924.  
  925. @@:    push    es            ; Set up for call to put_sprite()
  926.     push    bx
  927.     push    [si].y
  928.     push    [si].x
  929.     call    put_sprite
  930.     add    sp, 4            ; Clear the stack
  931.     pop    bx            ; ES:BX -> sprite pointer
  932.     pop    es
  933.     les    bx, dword ptr es:[bx].animate_ptr
  934.     mov    [si].sprite_ptr, bx
  935.     mov    [si].sprite_ptr+2, es
  936.  
  937. pre_next_sprite:
  938.     mov    si, [si].next_node    ; SI -> next sprite node in line
  939.     jmp    next_sprite
  940.  
  941. almost_done:
  942.     mov    ax, pre_max_x
  943.     cmp    ax, 640
  944.     jb    @F
  945.     mov    ax, 639
  946.     mov    pre_max_x, ax
  947. @@:    cmp    pre_min_x, ax
  948.     jb    @F
  949.     dec    ax
  950.     mov    pre_min_x, ax
  951. @@:    mov    ax, pre_max_y
  952.     cmp    ax, 200
  953.     jb    @F
  954.     mov    ax, 199
  955.     mov    pre_max_y, ax
  956. @@:    cmp    pre_min_y, ax
  957.     jb    @F
  958.     mov    pre_min_y, ax
  959.  
  960. @@:    mov    done_page_flip, 0
  961.     mov    do_page_flip, -1
  962.  
  963. done:    ret
  964. do_sprite_list endp
  965.  
  966. ; ****************************************************************************
  967. ; void CLEAR_SPRITE_LIST( void )
  968. ; Zeros out the present sprite list
  969. ; Given:
  970. ;    nothing
  971. ; Returns:
  972. ;    FIRST_SPRITE and SPRITE_LIST array are zeroed
  973.  
  974. clear_sprite_list proc uses di
  975.  
  976.     cld
  977.     mov    di, offset sprite_list
  978.     mov    ax, ds
  979.     mov    es, ax
  980.     xor    ax, ax
  981.     mov    first_sprite, ax
  982.     mov    cx, (MAX_SPRITES * (size sprite_node))/2
  983.     rep    stosw
  984.  
  985.     ret
  986. clear_sprite_list endp
  987.  
  988. ; ****************************************************************************
  989. ; int INSERT_SPRITE( ui X1,ui Y1, ui D_X,ui D_Y, ui PLUS_X,ui PLUS_Y,
  990. ;               ui THE_DEPTH, sprite_structure far *SPRITE )
  991. ; Inserts the first sprite of a sprite circle into the linked list of circles
  992. ; Given:
  993. ;    X1,Y1 = pixel location of the upper left corner of the sprite
  994. ;    D_X,D_Y = pixel location of the destination of the sprite
  995. ;    PLUS_X,PLUS_Y = pixels the sprite moves every page flip
  996. ;    THE_DEPTH = apparent distance of the sprite from the viewer
  997. ;    SPRITE -> sprite to insert
  998. ; Returns:
  999. ;    If 0, sprite pointer was inserted in the array
  1000. ;    else !0 if there is no room
  1001.  
  1002. insert_sprite proc uses si, x1:word,y1:word, d_x:word,d_y:word,\
  1003.                 plus_x:word,plus_y:word, the_depth:word,\
  1004.                 sprite:dword
  1005.  
  1006.     mov    cx, MAX_SPRITES
  1007.     mov    bx, (offset sprite_list) - (size sprite_node)
  1008. @@:    add    bx, size sprite_node
  1009.     mov    ax, [bx].sprite_ptr    ; See if this has been set yet
  1010.     or    ax, [bx].sprite_ptr+2
  1011.     loopnz    @B
  1012.     jnz    done_bad
  1013.  
  1014.     les    ax, sprite        ; ES:AX -> sprite location
  1015.     mov    [bx].sprite_ptr, ax    ; Save it
  1016.     mov    [bx].sprite_ptr+2, es
  1017.  
  1018.     mov    ax, x1            ; Set up the structure
  1019.     mov    [bx].x, ax
  1020.     mov    [bx].pre_x, ax
  1021.     mov    ax, y1
  1022.     mov    [bx].y, ax
  1023.     mov    [bx].pre_y, ax
  1024.     mov    ax, d_x
  1025.     mov    [bx].dest_x, ax
  1026.     mov    ax, d_y
  1027.     mov    [bx].dest_y, ax
  1028.     mov    ax, plus_x
  1029.     mov    [bx].adder_x, ax
  1030.     mov    ax, plus_y
  1031.     mov    [bx].adder_y, ax
  1032.     mov    ax, the_depth
  1033.     mov    [bx].depth, ax        ; This is used in the following loop
  1034.     mov    dx, bx            ; Save this s[rite entry for later
  1035.  
  1036.     mov    si, first_sprite    ; SI -> sprite furthest from the viewer
  1037.     mov    bx, offset first_sprite    ; BX -> previous sprite entry
  1038.     mov    cx, MAX_SPRITES
  1039. @@:    or    si, si            ; See if it's a NULL ptr
  1040.     jz    @F            ; Skip out if it is
  1041.     cmp    ax, [si].depth        ; See if farther from observer
  1042.     jnc    @F
  1043.     mov    bx, si            ; BX = this pointer
  1044.     mov    si, [si].next_node    ; SI -> next sprite node in line
  1045.     loop    @B
  1046. done_bad:
  1047.     mov    ax, -1            ; Indicate we had a problem
  1048.     jmp    short done
  1049.  
  1050. @@:    xchg    si, dx            ; SI -> sprite_list[i]
  1051.     mov    [si].next_node, dx
  1052.     cmp    bx, offset first_sprite
  1053.     jne    @F
  1054.     mov    [bx], si
  1055.     jmp    short done_good
  1056. @@:    mov    [bx].next_node, si
  1057. done_good:
  1058.     xor    ax, ax
  1059. done:    ret
  1060.  
  1061. insert_sprite endp
  1062.  
  1063. ; ****************************************************************************
  1064. ; void ADD_SPRITE( sprite_structure far *DEST, far *SOURCE )
  1065. ; Adds a self-relative sprite motion to the end of a sprite circle
  1066. ; Given:
  1067. ;    DEST -> sprite circle header
  1068. ;    SOURCE -> sprite to add on
  1069. ; Returns:
  1070. ;    SOURCE is added to the end of the sprite linked list and the
  1071. ;    circle ends are rejoined, may the circle be unbroken (ie Johnny Cash)
  1072.  
  1073. add_sprite proc uses si di ds, dest:dword, source:dword
  1074.  
  1075.     lds    si, dest
  1076.     les    di, source
  1077. next_sprite:
  1078.     mov    ax, [si].animate_ptr    ; See if this is the end of the line
  1079.     cmp    ax, word ptr dest
  1080.     jne    @F
  1081.     mov    ax, [si].animate_ptr+2
  1082.     cmp    ax, word ptr dest+2
  1083.     je    got_the_end
  1084. @@:    lds    si, [si].animate_ptr
  1085.     jmp    next_sprite
  1086.  
  1087. got_the_end:
  1088.     mov    [si].animate_ptr, di
  1089.     mov    [si].animate_ptr+2, es
  1090.     mov    ax, word ptr dest
  1091.     mov    es:[di].animate_ptr, ax
  1092.     mov    ax, word ptr dest+2
  1093.     mov    es:[di].animate_ptr+2, ax
  1094.  
  1095.     ret
  1096. add_sprite endp
  1097.  
  1098.     end
  1099.  
  1100.  
  1101. [LISTING THREE]
  1102.  
  1103. /******************************************************************************
  1104.     TITLE:    SPRITES.C
  1105.     Displays a sprite file on an EGA screen
  1106.     Written by: Rahner James, CS
  1107.                 of Ryu Consulting, Inc.
  1108. ******************************************************************************/
  1109. #include <stdio.h>
  1110. #include <dos.h>
  1111. #include <fcntl.h>
  1112. /******************************************************************************
  1113.         VARIOUS DEFINITIONS
  1114. ******************************************************************************/
  1115. #pragma pack(1)
  1116.  
  1117. typedef    unsigned char    uc;
  1118. typedef    unsigned int    ui;
  1119. typedef    unsigned long    ul;
  1120. /******************************************************************************
  1121.         EXTERNAL DECLARATIONS
  1122. ******************************************************************************/
  1123. extern    void ega_convert();
  1124. extern    ui ega_calculate( uc far * );
  1125. extern    void ega_install();
  1126. extern    void ega_clear_area( ui, ui, ui, ui );
  1127. /******************************************************************************
  1128.         GLOBAL DATA
  1129. ******************************************************************************/
  1130. ui    min_x=0, min_y=0, max_x=639, max_y=199;
  1131. /******************************************************************************
  1132.     long READ_ALL_FILE( uc *FILENAME, uc huge *BUFFER, ul BUFFER_SIZE )
  1133.     Opens and reads an entire sprite file
  1134.     Given:
  1135.         FILENAME -> name of sprite file to read
  1136.         BUFFER -> buffer to read the sprite file into
  1137.         BUFFER_SIZE = number of bytes the buffer can hold
  1138.     Returns:
  1139.         File is opened, read and closed
  1140.         Number of bytes read, if all went well
  1141.         If error, returns -1
  1142. ******************************************************************************/
  1143. long read_all_file( uc *filename, uc huge *buffer, ul buffer_size )
  1144. {
  1145.     long    rv = 0;
  1146.     ui    handle, dos_return, amount_read;
  1147.     ui    amount_to_read;
  1148.     if ( _dos_open( filename, O_RDONLY, &handle ) )
  1149.         return -1;
  1150.     while ( buffer_size )
  1151.     {
  1152.         amount_to_read = buffer_size<60000L ? buffer_size : 60000L;
  1153.         if ( _dos_read( handle, buffer+rv, amount_to_read, &amount_read ) )
  1154.         {
  1155.             rv = -1;
  1156.             break;
  1157.         }
  1158.         rv += amount_read;
  1159.         if ( amount_read < 60000 )
  1160.             break;
  1161.         buffer_size -= amount_read;
  1162.     }
  1163.     _dos_close( handle );
  1164.     return rv;
  1165. }
  1166.  
  1167. /******************************************************************************
  1168.     void DO_BACKGROUND( void )
  1169.     Sets up the background for the sprite visual screen
  1170.     Given:
  1171.         nothing
  1172.     Returns:
  1173.         visual sprite screen erased
  1174. ******************************************************************************/
  1175. void do_background( void )
  1176. {
  1177.     ega_clear_area( min_x, min_y, max_x, max_y );
  1178. }
  1179. /******************************************************************************
  1180.     uc SET_MODE( uc MODE_NUMBER )
  1181.     Sets the video mode
  1182.     Given:
  1183.         Mode number to set video to
  1184.     Returns:
  1185.         Present video mode number
  1186. ******************************************************************************/
  1187. uc set_mode( uc mode_number )
  1188. {
  1189.     uc rv;
  1190.     union REGS regs;
  1191.  
  1192.     regs.h.ah = 15;
  1193.     int86( 0x10, ®s, ®s );
  1194.     rv = regs.h.al;
  1195.  
  1196.     regs.h.ah = 0;
  1197.     regs.h.al = mode_number;
  1198.     int86( 0x10, ®s, ®s );
  1199.  
  1200.     return rv;
  1201. }
  1202. /******************************************************************************
  1203.     MAIN( int ARGC, uc *ARGV[] )
  1204.     Allocates memory, reads in a sprite file, displays the sprites
  1205.     until a key is pressed, frees up memory and interrupt vectors
  1206.     Given:
  1207.         ARGC = number of command line values, must be > 1
  1208.         ARGV[1] -> file name of the sprite file to display
  1209.     Returns:
  1210.         0 if all went well, otherwise numbered according to error
  1211. ******************************************************************************/
  1212. main( int argc, uc *argv[] )
  1213. {
  1214.     ui    i, x, y;
  1215.     uc    far *file_ptr, huge *sprite_start, huge *buffer_start;
  1216.     uc    huge *sprite_ptr[20];
  1217.     uc    old_mode;
  1218.     ui    memory_segment;
  1219.     ul    memory_size=0, file_size;
  1220. /* Check initial values and allocate memory for buffers */
  1221.     if ( argc<2 )
  1222.     {
  1223.         printf( "\nNo file name has been given\n" );
  1224.         exit( 1 );
  1225.     }
  1226.  
  1227.     if ( _dos_allocmem( -1, (ui *)&memory_size ) )
  1228.     {
  1229.         if ( _dos_allocmem( memory_size, &memory_segment ) )
  1230.         {
  1231.             printf( "\nMemory allocation error\n" );
  1232.             exit( 2 );
  1233.         }
  1234.     }
  1235.     else
  1236.     {
  1237.         memory_segment = memory_size;
  1238.         memory_size = 0xffff;
  1239.     }
  1240.     memory_size <<= 4;
  1241.     buffer_start = (uc huge *)((ul)memory_segment << 16L);
  1242. /* Read in the sprite file and then convert it to our intenal structure */
  1243.     file_ptr = buffer_start;
  1244.     if ( (file_size=read_all_file(argv[1],file_ptr,memory_size)) == -1 )
  1245.     {
  1246.         _dos_freemem( memory_segment );
  1247.         printf( "\nGot error reading %s.  Aborting.\n", argv[1] );
  1248.         exit( 3 );
  1249.     }
  1250.     clear_sprite_list();
  1251.     sprite_start = file_ptr + file_size;
  1252.     for ( i=0 ; i<20 && file_size ; ++i )
  1253.     {
  1254.         ega_convert( sprite_ptr[i]=sprite_start, file_ptr );
  1255.         x = ega_calculate( file_ptr );
  1256.         sprite_start += x;
  1257.         x = (ui)*file_ptr * (ui)*(file_ptr+2) + 4;
  1258.         file_ptr += x;
  1259.         if ( file_size > (ul)x )
  1260.             file_size -= (ul)x;
  1261.         else
  1262.             file_size = 0;
  1263.     }
  1264. /* Create linked list of sprite circles */
  1265.     insert_sprite( 100,100, 100,100, 0,0, 7, sprite_ptr[0] );
  1266.     for ( x=1 ; x<i ; ++x )
  1267.         add_sprite( sprite_ptr[0], sprite_ptr[x] );
  1268. /* Setup the EGA screen mode and interrupt vector */
  1269.     old_mode = set_mode( 0x10 );
  1270.     ega_install();
  1271. /* Process the sprite list until someone taps a key */
  1272.     while ( !kbhit() )
  1273.         do_sprite_list();
  1274. /* Restore screen and allocated memory to original state */
  1275.     ega_rip_out();
  1276.     set_mode( old_mode );
  1277.     _dos_freemem( memory_segment );
  1278.     exit( 0 );
  1279. }
  1280.  
  1281.  
  1282. [LISTING FOUR]
  1283.  
  1284. sprite.obj:    sprite.c
  1285.     cl /c sprite.c
  1286.  
  1287. ega_drv.obj:    ega_drv.asm
  1288.     masm ega_drv;
  1289.  
  1290. gen_asm.obj:    gen_asm.asm
  1291.     masm gen_asm;
  1292.  
  1293. sprite.exe:    sprite.obj ega_drv.obj gen_asm.obj
  1294.     link sprite+gen_asm+ega_drv;
  1295.  
  1296.  
  1297. Examplσ 1║ Samplσ codσ fo≥ writinτ bi⌠ ma≡ t∩ EG┴ memory
  1298.  
  1299. MOV       DX, 3C4h       ; DX -> Sequencer register
  1300. MOV       AL, 1          ; AL = index 1, Clocking Mode
  1301. OUT       DX, AL
  1302. INC       DX             ; DX -> Sequencer index portèMOV       AL, 5          ; AL = to put in Clocking Mode
  1303. OUT       DX, AL
  1304.  
  1305.  
  1306. Examplσ 2║ Replacinτ thσ codσ iε Examplσ 1
  1307.  
  1308. MOV       DX, 3C4h       ; DX -> Sequencer reg. pair
  1309. MOV       AX, 501h       ; AL = index 1, AH = value 5èOUT       DX, AX         ; Puts AL out 3C4h, then
  1310.                          ;  AH out 3C5h
  1311.  
  1312.